////////////////////////////////////////
//	File Header
//	Author: Stephen Ringer | stephen.ringer@gmail.com
//	File: SAGAD3D_vchache.h
//
////////////////////////////////////////
#pragma once
////////////////////////////////////////
//	File Includes
#include <d3d9.h>
#include "SAGA.h"
#include "SAGAD3DSkinManager.h"
//
////////////////////////////////////////

////////////////////////////////////////
//	Macros
#define NUM_CACHES 10
//
////////////////////////////////////////

////////////////////////////////////////
//	Struct Name: SAGASTATICBUFFER
//	Purpose:
//		for static vertex/index data
typedef struct SAGASTATICBUFFER_TYPE
{
	int nStride;
	UINT nSkinID;
	bool bIndis;
	int nNumVerts;
	int nNumIndis;
	int nNumTris;
	DWORD dwFVF;
	LPDIRECT3DVERTEXBUFFER9 pVB;
	LPDIRECT3DINDEXBUFFER9 pIB;
}SAGASTATICBUFFER;
//
////////////////////////////////////////

////////////////////////////////////////
//	Struct Name: SAGAINDEXBUFFER
//	Purpose:
//		for index data
typedef struct SAGAINDEXBUFFER_TYPE
{
	int nNumIndis;
	int nNumTris;
	LPDIRECT3DINDEXBUFFER9 pIB;
}SAGAINDEXBUFFER;
//
////////////////////////////////////////
class SAGAD3D;
////////////////////////////////////////
//	Class Name: SAGAD3DVCManager
//	Purpose:
//		Class to manage static and dynamic vertex bunches, optionally
//		using indices during rendering process
class SAGAD3DVCManager : public SAGAVertexCacheManager 
{
public:
	SAGAD3DVCManager(SAGAD3DSkinManager *pSkinMan, LPDIRECT3DDEVICE9 pDevice, SAGAD3D *pSAGAD3D, UINT nMaxVerts, UINT nMaxIndis, FILE *pLog);
	~SAGAD3DVCManager();

	HRESULT CreateStaticBuffer(	SAGAVERTEXID VertexID, UINT nSkinID, UINT nVerts, UINT nIndis, 
								const void *pVerts, const WORD *pIndis, UINT *pnID);

	HRESULT CreateIndexBuffer(UINT,const WORD*,UINT*);

	HRESULT Render(	SAGAVERTEXID VertexID, UINT  nVerts, UINT  nIndis, const void *pVerts, 
					const WORD *pIndis, UINT  SkinID);

	HRESULT RenderNaked(UINT, const void*, bool);

	HRESULT Render(UINT);
	HRESULT Render(UINT,UINT,UINT);
	HRESULT Render(UINT, UINT, UINT, UINT, UINT);

	HRESULT RenderPoints(	SAGAVERTEXID VertexID, UINT nVerts, const void *pVerts, 
							const SAGACOLOR *pClrl);

	HRESULT RenderLines(SAGAVERTEXID VertexID, UINT  nVerts, const void *pVerts, 
						const SAGACOLOR *pClrl, bool bStrip);

	HRESULT RenderLine(const float *fStart, const float *fEnd, const SAGACOLOR *pClr);
	HRESULT ForcedFlushAll();
	HRESULT ForcedFlush(SAGAVERTEXID VertexID);
	DWORD   GetActiveCache()       { return m_dwActiveCache; }
	void    SetActiveCache(DWORD dwID) { m_dwActiveCache = dwID; }
	SAGAD3D* GetSAGAD3D() { return m_pSAGAD3D; }
	void    InvalidateStates();
	SAGARENDERSTATE GetShadeMode();
private:
	SAGAD3DSkinManager *m_pSkinMan;
	LPDIRECT3DDEVICE9  m_pDevice;
	SAGAD3D            *m_pSAGAD3D;

	SAGASTATICBUFFER   *m_pSB;
	SAGAINDEXBUFFER    *m_pIB;
	UINT               m_nNumSB;
	UINT               m_nNumIB;
	SAGAD3DVCache      *m_CachePS[NUM_CACHES];    // position only
	SAGAD3DVCache      *m_CacheUU[NUM_CACHES];    // Untransformed Unlit
	SAGAD3DVCache      *m_CacheUL[NUM_CACHES];    // Untransformed Lit
	SAGAD3DVCache      *m_CacheCA[NUM_CACHES];    // character animation
	SAGAD3DVCache      *m_Cache3T[NUM_CACHES];    // three textures
	SAGAD3DVCache      *m_CacheTV[NUM_CACHES];    // uu with tanget
	DWORD              m_dwActiveCache;
	DWORD              m_dwActiveSB;   
	DWORD              m_dwActiveIB;
	FILE              *m_pLog;

	void Log(char *, ...);
};
//
////////////////////////////////////////

////////////////////////////////////////
//	Function Name: SAGAD3DVCache
//	Purpose:
//		Class for batching together polygons to be rendered in dynamic buffers.
//		Will flush content if requested or if max number of verts/indis in
//		cache is reached.
class SAGAD3DVCache 
{
public:

	SAGAD3DVCache(UINT nVertsMax, UINT nIndisMax, 
		UINT nStride, SAGAD3DSkinManager *pSkinMan,
		LPDIRECT3DDEVICE9 pDevice, SAGAD3DVCManager *pDad,
		DWORD dwID, DWORD dwFVF, FILE *pLog);

	~SAGAD3DVCache();

	HRESULT Flush(bool bUseShaders);

	HRESULT Add(UINT  nVerts, UINT nIndis, 
		const void *pVerts,
		const WORD *pIndis,
		bool  bUseShaders);

	void SetSkin(UINT  SkinID, bool bUseShader);
	bool UsesSkin(UINT SkinID) { return (m_SkinID == SkinID); }
	bool IsEmpty(void) { if (m_nNumVerts>0) return false; return true; }
	int  NumVerts(void) { return m_nNumVerts; }
private:
	LPDIRECT3DVERTEXBUFFER9  m_pVB;
	LPDIRECT3DINDEXBUFFER9   m_pIB;
	LPDIRECT3DDEVICE9        m_pDevice;
	SAGAD3DSkinManager       *m_pSkinMan;
	SAGAD3DVCManager         *m_pDad;
	SAGASKIN                  m_Skin;
	UINT                     m_SkinID;
	DWORD                    m_dwID;
	DWORD                    m_dwFVF;
	FILE                    *m_pLog;

	UINT  m_nNumVertsMax;   // maximum verts in buffer
	UINT  m_nNumIndisMax;   // maximum indices in buffer
	UINT  m_nNumVerts;      // actual number in buffer
	UINT  m_nNumIndis;      // actual number in buffer
	UINT  m_nStride;        // stride of one vertex element

	void Log(char *, ...);
};
//
////////////////////////////////////////